////////////////////////////////////////////////////////////////////////////////
// Copyright 2010 Michael Schmalle - Teoti Graphix, LLC
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0 
// 
// Unless required by applicable law or agreed to in writing, software 
// distributed under the License is distributed on an "AS IS" BASIS, 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and 
// limitations under the License
// 
// Author: Michael Schmalle, Principal Architect
// mschmalle at teotigraphix dot com
////////////////////////////////////////////////////////////////////////////////

package org.teotigraphix.swizplugin.core
{

import mx.rpc.IResponder;
import mx.rpc.Responder;

import org.teotigraphix.swizplugin.api.IExecutableRequest;
import org.teotigraphix.swizplugin.registry.IExtensionDescriptor;

/**
 * An executable request object that allows responders to be registered
 * and multiple apply method using either a <code>Class</code> reference
 * or an <code>IResponder</code> instance.
 * 
 * @author Michael Schmalle
 * @copyright Teoti Graphix, LLC
 * @productversion 1.0
 */
public class ExecutableRequest implements IExecutableRequest
{
	//--------------------------------------------------------------------------
	//
	//  Private :: Variables
	//
	//--------------------------------------------------------------------------
	
	/**
	 * @private
	 */
	private var _responders:Array;
	
	/**
	 * @private
	 */
	private var _instance:Object;
	
	/**
	 * @private
	 */
	private var _type:Class;
	
	//--------------------------------------------------------------------------
	//
	//  Public :: Properties
	//
	//--------------------------------------------------------------------------
	
	//----------------------------------
	//  isBean
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _isBean:Boolean;
	
	/**
	 * @copy org.teotigraphix.swizplugin.api.IExecutableRequest#isBean
	 */
	public function get isBean():Boolean
	{
		return _isBean;
	}
	
	/**
	 * @private
	 */	
	public function set isBean(value:Boolean):void
	{
		_isBean = value;
	}
	
	//----------------------------------
	//  autoCreate
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _autoCreate:Boolean = true;
	
	/**
	 * TODO Docme
	 */
	public function get autoCreate():Boolean
	{
		return _autoCreate;
	}
	
	/**
	 * @private
	 */	
	public function set autoCreate(value:Boolean):void
	{
		_autoCreate = value;
	}
	
	//----------------------------------
	//  descriptor
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _descriptor:IExtensionDescriptor;
	
	/**
	 * @copy org.teotigraphix.swizplugin.api.IExecutableRequest#descriptor
	 */
	public function get descriptor():IExtensionDescriptor
	{
		return _descriptor;
	}
	
	/**
	 * @private
	 */
	public function set descriptor(value:IExtensionDescriptor):void
	{
		_descriptor = value;
	}
	
	//----------------------------------
	//  data
	//----------------------------------
	
	/**
	 * @private
	 */
	private var _data:Object;
	
	/**
	 * @copy org.teotigraphix.swizplugin.api.IExecutableRequest#data
	 */
	public function get data():Object
	{
		return _data;
	}
	
	/**
	 * @private
	 */
	public function set data(value:Object):void
	{
		_data = value;
	}
	
	//----------------------------------
	//  instance
	//----------------------------------
	
	/**
	 * @copy org.teotigraphix.swizplugin.api.IExecutableRequest#instance
	 */
	public function get instance():Object
	{
		return _instance;
	}
	
	//----------------------------------
	//  type
	//----------------------------------
	
	/**
	 * The requested <code>Class</code> reference, <code>null</code> if not.
	 */
	public function get type():Class
	{
		return _type;
	}
	
	//--------------------------------------------------------------------------
	//
	//  Constructor
	//
	//--------------------------------------------------------------------------
	
	/**
	 * Creates a new <code>ExecutableRequest</code> instance.
	 * 
	 * @param type A Class reference that was requested.
	 * @param instance A Class instance that was requested.
	 */
	public function ExecutableRequest(type:Class = null, 
									  instance:Object = null)
	{
		super();
		
		_type = type;
		_instance = instance;
	}
	
	//--------------------------------------------------------------------------
	//
	//  Public :: Methods
	//
	//--------------------------------------------------------------------------
	
	/**
	 * Adds a result responder only.
	 * 
	 * <p>When the handler Function is called, this request token will be
	 * passed if the <code>apply()</code> method is used. If the 
	 * <code>applyClass()</code> method is used, the <code>clazz</code>
	 * will be passed, if the <code>applyInstance()</code> method is used,
	 * the <code>instance</code> will be passed to the handler.</p>
	 * 
	 * @param handler A Function that will be called when an apply
	 * method is called.
	 * 
	 * @see #applyInstance()
	 * @see #applyClass()
	 * @see #apply()
	 */
	public function addListener(result:Function, fault:Function):void
	{
		addResponder(new Responder(result, fault));
	}
	
	/**
	 * Sets the <code>instance</code> property, the method only allows one
	 * call, any calls after the first will just return.
	 * 
	 * @param instance A Class instance that was requested.
	 */
	public function setInstance(instance:Object):void
	{
		if (_instance != null)
			return;
		
		_instance = instance;
	}
	
	/**
	 * Sets the <code>type</code> property, the method only allows one
	 * call, any calls after the first will just return.
	 * 
	 * @param type A Class reference that was requested.
	 */
	public function setType(type:Class):void
	{
		if (_type != null)
			return;
		
		_type = type;
	}
	
	/**
	 * Adds an <code>IResponder</code> to the responders array.
	 * 
	 * @param An <code>IResponder</code> instance with either a result handler,
	 * fault handler or both.
	 */
	public function addResponder(responder:IResponder):void
	{
		if (_responders == null)
			_responders = [];
		
		_responders.push(responder);
	}
	
	/**
	 * Instantly applies the <code>instance</code> property based on the parameter
	 * passed and calls all registered responder's result handlers.
	 * 
	 * @param instance A Class instance that was requested.
	 */
	public function applyInstance(instance:Object):void
	{
		setInstance(instance);
		
		if (_responders != null)
			return;
		
		for (var i:int = 0; i < _responders.length; i++)
		{
			var responder:IResponder = _responders[i];
			if (responder != null)
				responder.result(instance);
		}
	}
	
	/**
	 * Instantly applies the <code>clazz</code> property based on the parameter
	 * passed and calls all registered responder's result handlers.
	 * 
	 * @param instance A Class reference that was requested.
	 */
	public function applyClass(type:Class):void
	{
		setType(type);
		
		if (_responders != null)
			return;
		
		for (var i:int = 0; i < _responders.length; i++)
		{
			var responder:IResponder = _responders[i];
			if (responder != null)
				responder.result(type);
		}
	}	
	
	/**
	 * Applies all responder's result handlers after the <code>clazz</code> 
	 * or <code>instance</code> has been set.
	 *  
	 * <p>The result handler will be pass this instance as the single 
	 * argument.</p>
	 */
	public function apply():void
	{
		if (_responders != null)
		{
			for (var i:uint = 0; i < _responders.length; i++)
			{
				var responder:IResponder = _responders[i];
				if (responder != null)
					responder.result(this);
			}
		}
	}
}
}